Kuasai User Timing API untuk membuat metrik kinerja khusus dan bermakna. Lampaui web vitals standar untuk menemukan hambatan dan mengoptimalkan pengalaman pengguna.
Menguasai Frontend Performance: Selami Lebih Dalam User Timing API
Dalam lanskap digital modern, kinerja frontend bukanlah kemewahan; ini adalah persyaratan mendasar untuk kesuksesan. Untuk audiens global, situs web yang lambat dan tidak responsif dapat menyebabkan frustrasi pengguna, penurunan keterlibatan, dan dampak negatif langsung pada hasil bisnis. Kami memiliki metrik standar yang sangat baik seperti Core Web Vitals (Largest Contentful Paint, First Input Delay, Cumulative Layout Shift) yang memberi kita pemahaman dasar tentang pengalaman pengguna. Namun, metrik ini, meskipun penting, hanya menceritakan sebagian dari cerita.
Bagaimana dengan kinerja fitur khusus aplikasi? Berapa lama hasil pencarian muncul setelah pengguna mengetik kueri? Berapa lama waktu yang dibutuhkan komponen visualisasi data kompleks Anda untuk dirender setelah menerima data dari API? Bagaimana fitur baru memengaruhi kecepatan transisi rute aplikasi halaman tunggal (SPA) Anda? Metrik standar tidak dapat menjawab pertanyaan-pertanyaan granular dan penting bagi bisnis ini. Di sinilah User Timing API berperan, memberdayakan pengembang untuk membuat pengukuran kinerja khusus dan berpresisi tinggi yang disesuaikan dengan aplikasi unik mereka.
Panduan komprehensif ini akan memandu Anda melalui semua yang perlu Anda ketahui untuk memanfaatkan User Timing API, mulai dari konsep dasar marks dan measures hingga teknik lanjutan menggunakan PerformanceObserver. Pada akhirnya, Anda akan diperlengkapi untuk melampaui metrik generik dan mulai menceritakan kisah kinerja unik aplikasi Anda.
Apa itu Performance API? Konteks yang Lebih Luas
Sebelum kita menyelami User Timing, penting untuk memahami bahwa ini adalah bagian dari rangkaian alat yang lebih besar yang secara kolektif dikenal sebagai Performance API. API browser ini menyediakan akses ke data waktu beresolusi tinggi yang terkait dengan navigasi, pemuatan sumber daya, dan banyak lagi. Objek `window.performance` global adalah titik masuk Anda ke perangkat yang hebat ini.
Performance API terdiri dari beberapa antarmuka, termasuk:
- Navigation Timing: Menyediakan informasi waktu terperinci tentang proses navigasi dokumen, seperti waktu yang dihabiskan untuk pencarian DNS, jabat tangan TCP, dan menerima byte pertama.
- Resource Timing: Menawarkan data waktu jaringan terperinci untuk setiap sumber daya yang dimuat oleh halaman, termasuk gambar, skrip, dan file CSS.
- Paint Timing: Mengekspos waktu untuk First Paint dan First Contentful Paint.
- User Timing: Fokus artikel kita, yang memungkinkan pengembang untuk membuat stempel waktu (marks) khusus mereka sendiri dan mengukur durasi di antara mereka (measures).
API ini bekerja sama untuk memberikan pandangan holistik tentang kinerja aplikasi Anda. Tujuan kami hari ini adalah untuk menguasai bagian User Timing, yang memberi kita kekuatan untuk menambahkan pos pemeriksaan khusus kita sendiri ke timeline kinerja ini.
Konsep Inti: Marks dan Measures
User Timing API sangat sederhana, berkisar pada dua konsep mendasar: marks dan measures. Anggap saja seperti menggunakan stopwatch. Anda menekan tombol untuk menandai waktu mulai, dan Anda menekannya lagi untuk menandai waktu berakhir. Durasi antara kedua tekanan itu adalah pengukuran Anda.
Membuat Performance Marks: `performance.mark()`
'Mark' adalah stempel waktu beresolusi tinggi bernama yang dicatat pada titik tertentu dalam eksekusi aplikasi Anda. Ini seperti menancapkan bendera pada timeline kinerja Anda. Anda dapat membuat sebanyak mungkin marks yang Anda butuhkan untuk mengidentifikasi momen-momen penting dalam perjalanan pengguna atau siklus hidup komponen.
Sintaksnya mudah:
performance.mark(markName, [markOptions]);
markName: String yang mewakili nama unik untuk mark Anda. Pilih nama deskriptif!markOptions(opsional): Objek yang dapat berisi propertidetailuntuk melampirkan metadata tambahan, danstartTimeuntuk menentukan stempel waktu khusus.
Contoh Dasar: Menandai Suatu Peristiwa
Katakanlah kita ingin menandai awal dari panggilan fungsi penting.
function processLargeDataset() {
// Tancapkan bendera tepat sebelum pekerjaan berat dimulai
performance.mark('processLargeDataset:start');
// ... logika komputasi berat ...
console.log('Pemrosesan dataset selesai.');
// Tancapkan bendera lain saat selesai
performance.mark('processLargeDataset:end');
}
processLargeDataset();
Dalam contoh ini, kita telah membuat dua stempel waktu di timeline kinerja browser: `processLargeDataset:start` dan `processLargeDataset:end`. Saat ini, mereka hanyalah titik-titik waktu. Kekuatan sejati mereka dibuka ketika kita menggunakannya untuk membuat measure.
Menambahkan Konteks dengan Properti `detail`
Terkadang, stempel waktu saja tidak cukup. Anda mungkin ingin menyertakan konteks tambahan tentang apa yang terjadi pada saat itu. Properti `detail` sangat cocok untuk ini. Ini dapat menyimpan data apa pun yang dapat dikloning secara struktural (seperti objek, array, string, angka).
Bayangkan kita menandai awal dari render komponen dan ingin tahu berapa banyak item yang dirender.
function renderProductList(products) {
const itemCount = products.length;
performance.mark('ProductList:render:start', {
detail: {
itemCount: itemCount,
source: 'initial-load'
}
});
// ... logika rendering komponen ...
performance.mark('ProductList:render:end');
}
const sampleProducts = new Array(1000).fill(0);
renderProductList(sampleProducts);
Konteks tambahan ini sangat berharga saat menganalisis data kinerja nanti. Anda dapat, misalnya, menghubungkan waktu render dengan jumlah item untuk melihat apakah ada hubungan linier atau eksponensial.
Membuat Performance Measures: `performance.measure()`
'Measure' menangkap durasi antara dua titik waktu. Ini adalah perhitungan yang memberi tahu Anda "berapa lama" sesuatu berlangsung. Paling umum, Anda akan mengukur waktu antara dua mark khusus Anda.
Sintaksnya memiliki beberapa variasi:
performance.measure(measureName, startMarkOrOptions, [endMark]);
measureName: String yang mewakili nama unik untuk pengukuran Anda.startMarkOrOptions(opsional): String dengan nama mark awal. Juga dapat berupa objek opsi dengan `start`, `end`, `duration`, dan `detail`.endMark(opsional): String dengan nama mark akhir.
Contoh Dasar: Mengukur Durasi Fungsi
Mari kita bangun di atas contoh `processLargeDataset` kita dan benar-benar mengukur berapa lama waktu yang dibutuhkan.
function processLargeDataset() {
performance.mark('processLargeDataset:start');
// ... logika komputasi berat ...
performance.mark('processLargeDataset:end');
// Sekarang, buat measure
performance.measure(
'processLargeDataset:duration',
'processLargeDataset:start',
'processLargeDataset:end'
);
}
processLargeDataset();
Setelah kode ini berjalan, buffer kinerja browser akan berisi entri baru bernama `processLargeDataset:duration`. Entri ini akan memiliki properti `duration` yang menyimpan waktu yang tepat, dalam milidetik, yang berlalu antara mark mulai dan akhir.
Skenario Pengukuran Tingkat Lanjut
Metode `measure()` sangat fleksibel. Anda tidak selalu harus menyediakan dua marks.
- Dari Awal Navigasi ke Mark: Anda dapat mengukur waktu dari saat navigasi halaman dimulai hingga salah satu mark khusus Anda. Ini sangat berguna untuk mengukur hal-hal seperti "Waktu ke Komponen Interaktif".
// Ukur dari awal navigasi hingga komponen utama siap performance.measure('timeToInteractiveHeader', 'navigationStart', 'headerComponent:ready'); - Dari Mark ke Sekarang: Jika Anda menghilangkan `endMark`, measure akan dihitung dari `startMark` Anda hingga waktu saat ini.
// Ukur dari mark mulai hingga baris kode ini dieksekusi performance.measure('timeSinceDataRequest', 'api:fetch:start'); - Menggunakan Objek Opsi: Anda juga dapat meneruskan objek konfigurasi untuk mendefinisikan measure, yang berguna untuk menambahkan properti `detail`.
performance.measure('complexRender:duration', { start: 'complexRender:start', end: 'complexRender:end', detail: { renderType: 'canvas' } });
Mengakses dan Membersihkan Entri Kinerja
Membuat marks dan measures hanyalah setengah dari pertempuran. Anda memerlukan cara untuk mengambil data ini untuk menganalisisnya. Objek `performance` menyediakan beberapa metode untuk ini.
performance.getEntries(): Mengembalikan array dari semua entri kinerja dalam buffer (termasuk waktu sumber daya, waktu navigasi, dll.).performance.getEntriesByType(type): Mengembalikan array entri dari tipe tertentu. Anda paling sering akan menggunakan `performance.getEntriesByType('mark')` dan `performance.getEntriesByType('measure')`.performance.getEntriesByName(name, [type]): Mengembalikan array entri dengan nama tertentu (dan opsional, tipe tertentu).
Contoh: Mencatat Measures ke Konsol
// Setelah menjalankan contoh sebelumnya...
const allMeasures = performance.getEntriesByType('measure');
console.log(allMeasures);
// Objek entri measure terlihat seperti ini:
// {
// "name": "processLargeDataset:duration",
// "entryType": "measure",
// "startTime": 12345.67,
// "duration": 150.89
// }
const specificMeasure = performance.getEntriesByName('processLargeDataset:duration');
console.log(`Pemrosesan membutuhkan waktu: ${specificMeasure[0].duration}ms`);
Penting: Membersihkan Buffer Kinerja
Buffer kinerja browser tidak tak terbatas. Untuk mencegah kebocoran memori dan menjaga pengukuran Anda tetap relevan, praktik terbaik adalah membersihkan marks dan measures yang telah Anda buat setelah Anda selesai dengannya.
performance.clearMarks([name]): Membersihkan semua marks, atau hanya marks dengan nama yang ditentukan.performance.clearMeasures([name]): Membersihkan semua measures, atau hanya measures dengan nama yang ditentukan.
Pola umum adalah mengambil data, memproses atau mengirimkannya, dan kemudian membersihkannya.
function analyzeAndClear() {
const myMeasures = performance.getEntriesByName('processLargeDataset:duration');
// Kirim myMeasures ke layanan analitik...
sendToAnalytics(myMeasures);
// Bersihkan untuk membebaskan memori
performance.clearMarks('processLargeDataset:start');
performance.clearMarks('processLargeDataset:end');
performance.clearMeasures('processLargeDataset:duration');
}
Kasus Penggunaan Nyata dan Praktis untuk User Timing
Sekarang kita memahami mekanismenya, mari kita jelajahi bagaimana menerapkan User Timing API untuk memecahkan tantangan kinerja dunia nyata. Contoh-contoh ini agnostik terhadap kerangka kerja dan dapat diadaptasi ke tumpukan frontend apa pun.
1. Mengukur Durasi Panggilan API
Memahami berapa lama aplikasi Anda menunggu data sangat penting. Anda dapat dengan mudah membungkus logika pengambilan data Anda dengan marks dan measures.
async function fetchUserData(userId) {
const markStart = `api:getUser:${userId}:start`;
const markEnd = `api:getUser:${userId}:end`;
const measureName = `api:getUser:${userId}:duration`;
performance.mark(markStart);
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return await response.json();
} catch (error) {
console.error('Fetch error:', error);
// Anda bahkan dapat menambahkan detail tentang kesalahan!
performance.mark(markEnd, { detail: { status: 'error', message: error.message } });
} finally {
// Pastikan mark akhir dan measure selalu dibuat
if (performance.getEntriesByName(markEnd).length === 0) {
performance.mark(markEnd, { detail: { status: 'success' } });
}
performance.measure(measureName, markStart, markEnd);
}
}
fetchUserData('123');
Pola ini memberikan waktu yang tepat untuk setiap panggilan API, memungkinkan Anda mengidentifikasi titik akhir yang lambat langsung dari data pengguna nyata.
2. Melacak Waktu Render Komponen di SPA
Untuk kerangka kerja seperti React, Vue, atau Angular, mengukur waktu yang dibutuhkan komponen untuk dipasang dan dirender adalah kasus penggunaan utama. Ini membantu mengidentifikasi komponen kompleks yang mungkin memperlambat aplikasi Anda.
Contoh dengan React Hooks:
import React, { useLayoutEffect, useEffect, useRef } from 'react';
function MyHeavyComponent({ data }) {
const componentId = useRef(`MyHeavyComponent-${Math.random()}`).current;
const markStartName = `${componentId}:render:start`;
const markEndName = `${componentId}:render:end`;
const measureName = `${componentId}:render:duration`;
// useLayoutEffect berjalan secara sinkron setelah semua mutasi DOM.
// Ini adalah tempat yang sempurna untuk menandai awal pengukuran render.
useLayoutEffect(() => {
performance.mark(markStartName);
}, []); // Jalankan hanya pada pemasangan awal
// useEffect berjalan secara asinkron setelah render dikomit ke layar.
// Ini adalah tempat yang baik untuk menandai akhir.
useEffect(() => {
performance.mark(markEndName);
performance.measure(measureName, markStartName, markEndName);
// Catat hasilnya untuk demonstrasi
const measure = performance.getEntriesByName(measureName)[0];
if (measure) {
console.log(`${measureName} membutuhkan waktu ${measure.duration}ms`);
}
// Pembersihan
performance.clearMarks(markStartName);
performance.clearMarks(markEndName);
performance.clearMeasures(measureName);
}, []); // Jalankan hanya pada pemasangan awal
return (
// ... JSX untuk komponen berat ...
);
}
3. Mengkuantifikasi Perjalanan Pengguna yang Kritis
Penggunaan User Timing yang paling berdampak adalah mengukur interaksi pengguna multi-langkah yang penting bagi bisnis Anda. Ini melampaui metrik teknis sederhana dan mengukur kecepatan yang dirasakan dari fungsionalitas inti aplikasi Anda.
Pertimbangkan proses pembayaran e-commerce:
const checkoutButton = document.getElementById('checkout-btn');
checkoutButton.addEventListener('click', () => {
// 1. Pengguna mengklik tombol 'checkout'
performance.mark('checkout:journey:start');
// ... kode untuk memvalidasi keranjang, menavigasi ke halaman pembayaran, dll. ...
});
// Di halaman pembayaran, setelah formulir pembayaran dirender dan interaktif
function onPaymentFormReady() {
performance.mark('checkout:paymentForm:ready');
performance.measure('checkout:timeToPaymentForm', 'checkout:journey:start', 'checkout:paymentForm:ready');
}
// Setelah pembayaran berhasil diproses dan layar konfirmasi ditampilkan
function onPaymentSuccess() {
performance.mark('checkout:journey:end');
performance.measure('checkout:totalJourney:duration', 'checkout:journey:start', 'checkout:journey:end');
// Sekarang Anda memiliki dua metrik yang kuat untuk dianalisis dan dioptimalkan.
}
4. A/B Testing Peningkatan Kinerja
Ketika Anda merefaktor sepotong kode atau memperkenalkan algoritma baru, bagaimana Anda membuktikan bahwa itu benar-benar lebih cepat untuk pengguna nyata? User Timing menyediakan data objektif untuk pengujian A/B.
Bayangkan Anda memiliki dua algoritma penyortiran yang berbeda yang ingin Anda uji:
function sortProducts(products, algorithmVersion) {
const markStart = `sort:v${algorithmVersion}:start`;
const markEnd = `sort:v${algorithmVersion}:end`;
const measureName = `sort:v${algorithmVersion}:duration`;
performance.mark(markStart);
if (algorithmVersion === 'A') {
// ... jalankan algoritma penyortiran lama ...
} else {
// ... jalankan algoritma penyortiran baru yang dioptimalkan ...
}
performance.mark(markEnd);
performance.measure(measureName, markStart, markEnd);
}
// Berdasarkan bendera pengujian A/B, Anda akan memanggil salah satu atau yang lain.
// Nanti, dalam analitik Anda, Anda dapat membandingkan durasi rata-rata dari
// 'sort:vA:duration' vs 'sort:vB:duration' untuk melihat mana yang lebih cepat.
Memvisualisasikan dan Menganalisis Metrik Kustom Anda
Membuat metrik khusus tidak berguna jika Anda tidak menganalisis data. Ada dua cara utama untuk mendekati ini: secara lokal selama pengembangan dan diagregasi dalam produksi.
Menggunakan Alat Pengembang Browser
Browser modern seperti Chrome dan Firefox memiliki dukungan yang sangat baik untuk memvisualisasikan marks dan measures User Timing di alat pembuatan profil kinerja mereka.
- Buka Alat Pengembang browser Anda (F12 atau Ctrl+Shift+I).
- Buka tab Performance.
- Mulai merekam profil dan kemudian lakukan tindakan di aplikasi Anda yang memicu marks dan measures khusus Anda.
- Hentikan perekaman.
Dalam tampilan timeline, Anda akan menemukan baris khusus yang disebut Timings. Marks khusus Anda akan muncul sebagai garis vertikal, dan measures Anda akan ditampilkan sebagai bilah berwarna yang menunjukkan durasinya. Mengarahkan kursor ke atasnya akan mengungkapkan nama dan waktu yang tepat. Ini adalah cara yang sangat ampuh untuk men-debug masalah kinerja selama pengembangan.
Mengirim Data ke Layanan Analitik dan RUM
Untuk pemantauan produksi, Anda perlu mengumpulkan data ini dari pengguna Anda dan mengirimkannya ke lokasi pusat untuk agregasi dan analisis. Ini adalah bagian inti dari Real User Monitoring (RUM).
Alur kerja umumnya adalah:
- Kumpulkan measures kinerja yang Anda minati.
- Format mereka ke dalam payload yang sesuai (misalnya, JSON).
- Kirim payload ke titik akhir analitik. Ini bisa berupa layanan pihak ketiga seperti Datadog, New Relic, Sentry, atau bahkan Google Analytics (melalui peristiwa khusus), atau backend khusus yang Anda kendalikan.
function sendPerformanceData() {
// Kami hanya peduli dengan measures aplikasi khusus kami
const appMeasures = performance.getEntriesByType('measure').filter(
(entry) => entry.name.startsWith('app:') // Gunakan konvensi penamaan!
);
if (appMeasures.length > 0) {
const payload = JSON.stringify(appMeasures.map(measure => ({
name: measure.name,
duration: measure.duration,
startTime: measure.startTime,
details: measure.detail, // Kirim konteks kaya kami
path: window.location.pathname // Tambahkan lebih banyak konteks
})));
// Gunakan navigator.sendBeacon untuk pengiriman data yang andal dan non-pemblokiran
navigator.sendBeacon('https://analytics.example.com/performance', payload);
// Bersihkan measures yang telah dikirim
appMeasures.forEach(measure => {
performance.clearMeasures(measure.name);
// Juga bersihkan marks terkait
});
}
}
// Panggil fungsi ini pada waktu yang tepat, misalnya, ketika halaman akan dibongkar
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
sendPerformanceData();
}
});
Teknik Tingkat Lanjut dan Praktik Terbaik
Untuk benar-benar menguasai User Timing API, mari kita lihat beberapa fitur tingkat lanjut dan praktik terbaik yang akan membuat instrumentasi Anda lebih kuat dan efisien.
Menggunakan `PerformanceObserver` untuk Pemantauan Asinkron
Metode `getEntries*()` mengharuskan Anda untuk secara manual melakukan polling buffer kinerja. Ini memiliki dua kekurangan: Anda mungkin menjalankan pemeriksaan Anda terlalu lambat dan kehilangan entri jika buffer telah terisi dan dibersihkan, dan polling itu sendiri dapat memiliki biaya kinerja kecil. Solusi modern yang disukai adalah `PerformanceObserver`.
`PerformanceObserver` memungkinkan Anda untuk berlangganan peristiwa entri kinerja. Fungsi callback Anda akan dipanggil secara asinkron setiap kali entri baru dari tipe yang Anda amati dicatat.
// 1. Buat fungsi callback untuk menangani entri baru
const observerCallback = (list) => {
for (const entry of list.getEntries()) {
console.log('Measure baru diamati:', entry.name, entry.duration);
// Di sini Anda dapat segera mengirim entri ke layanan analitik Anda
// tanpa perlu melakukan polling atau menunggu.
}
};
// 2. Buat instance observer
const observer = new PerformanceObserver(observerCallback);
// 3. Mulai amati tipe entri 'mark' dan 'measure'
// Opsi 'buffered: true' memastikan Anda mendapatkan entri yang dibuat
// *sebelum* observer didaftarkan.
observer.observe({ entryTypes: ['mark', 'measure'], buffered: true });
// Sekarang, setiap kali performance.mark() atau performance.measure() dipanggil di mana saja
// di aplikasi Anda, observerCallback akan dipicu dengan entri baru.
// Untuk berhenti mengamati nanti:
// observer.disconnect();
Menggunakan `PerformanceObserver` lebih efisien, lebih andal, dan harus menjadi pilihan default Anda untuk mengumpulkan data kinerja di lingkungan produksi.
Tetapkan Konvensi Penamaan yang Jelas
Saat aplikasi Anda tumbuh, Anda akan mengumpulkan banyak metrik khusus. Tanpa konvensi penamaan yang konsisten, data Anda akan menjadi sulit difilter dan dianalisis. Adopsi pola yang memberikan konteks.
Konvensi yang baik bisa jadi: [appName]:[featureOrComponent]:[eventName]:[status]
ecom:ProductGallery:render:startecom:ProductGallery:render:endecom:ProductGallery:render:durationadmin:DataTable:fetchApi:startadmin:DataTable:fetchApi:duration
Struktur ini membuatnya mudah untuk memfilter semua metrik yang terkait dengan `ProductGallery` atau untuk menemukan semua durasi `fetchApi` di seluruh aplikasi.
Abstrak ke dalam Layanan Utilitas
Untuk memastikan konsistensi dan mengurangi boilerplate, bungkus panggilan `performance` di modul atau layanan utilitas Anda sendiri. Ini juga membuatnya mudah untuk mengaktifkan atau menonaktifkan pemantauan kinerja berdasarkan lingkungan.
// performance-service.js
const IS_PERFORMANCE_MONITORING_ENABLED = process.env.NODE_ENV === 'production' || window.location.search.includes('perf=true');
export const perfMark = (name, options) => {
if (!IS_PERFORMANCE_MONITORING_ENABLED) return;
performance.mark(name, options);
};
export const perfMeasure = (name, start, end) => {
if (!IS_PERFORMANCE_MONITORING_ENABLED) return;
performance.measure(name, start, end);
};
export const startJourney = (name) => {
perfMark(`${name}:start`);
};
export const endJourney = (name) => {
const startMark = `${name}:start`;
const endMark = `${name}:end`;
const measureName = `${name}:duration`;
perfMark(endMark);
perfMeasure(measureName, startMark, endMark);
// Opsional, bersihkan marks di sini
};
// Di komponen Anda:
// import { startJourney, endJourney } from './performance-service';
// startJourney('ecom:checkout');
// ...later...
// endJourney('ecom:checkout');
Kesimpulan: Mengambil Kendali Atas Kisah Kinerja Aplikasi Anda
Meskipun metrik standar seperti Core Web Vitals memberikan pemeriksaan kesehatan penting untuk situs web Anda, mereka tidak menjelaskan kinerja fitur dan interaksi yang membuat aplikasi Anda unik. User Timing API adalah jembatan yang menutup kesenjangan ini. Ini memberikan mekanisme yang sederhana namun sangat kuat untuk mengukur apa yang benar-benar penting bagi pengguna dan bisnis Anda.
Dengan menerapkan marks dan measures khusus, Anda mengubah optimasi kinerja dari permainan tebak-tebakan menjadi ilmu berbasis data. Anda dapat menentukan fungsi, komponen, atau alur pengguna yang tepat yang menyebabkan hambatan, memvalidasi dampak upaya refactoring Anda dengan angka objektif, dan pada akhirnya membangun pengalaman yang lebih cepat dan lebih menyenangkan bagi audiens global Anda.
Mulailah dari yang kecil. Identifikasi perjalanan pengguna paling penting dalam aplikasi Anda—baik itu mencari produk, mengirimkan formulir, atau memuat dasbor data. Instrumentasikan dengan `performance.mark()` dan `performance.measure()`. Analisis hasilnya di alat pengembang Anda. Setelah Anda melihat kejelasan yang diberikannya, Anda akan diberdayakan untuk menceritakan kisah kinerja lengkap aplikasi Anda, satu metrik khusus pada satu waktu.